package cn.edu.ecut.controller;

import cn.edu.ecut.dao.StudentDao;
import cn.edu.ecut.entity.Student;
import com.mozicoding.foundation.support.EncryptHelper;
import com.mozicoding.foundation.support.EncryptType;
import com.mozicoding.foundation.support.GraphicHelper;
import com.mozicoding.web.context.ParameterHolder;
import com.mozicoding.web.context.RequestHolder;
import com.mozicoding.web.context.ResponseHolder;
import com.mozicoding.web.support.Controller;
import com.mozicoding.web.support.RedirectAttributes;
import com.mozicoding.web.support.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.OutputStream;

@Controller( path = "/student" )
public class StudentController {

    // 声明一个表示提示信息的属性名称的常量，以后就可以通过该常量来设置提示信息和取出提示信息
    private static final String MESSAGE_NAME = "message" ;
    // 声明一个表示会话对象中所设置的验证码属性的名称的常量
    private static final String CAPTCHA_NAME = "captcha" ;
    // 用来表示登录后的学生对象绑定到会话对象时使用的 属性名称
    private static final String SIGN_IN_NAME = "student" ;

    // 用来访问数据库的对象，负责将学生对象保存到数据库，负责从数据库取出数据包装成学生对象
    private StudentDao studentDao = new StudentDao();

    @RequestMapping( path = "/page/sign/up" )
    public String signUpPage(){
        return "/WEB-INF/assets/sign-up.html" ;
    }

    @RequestMapping( path = "/page/sign/in" )
    public String signInPage(){
        return "/WEB-INF/assets/sign-in.html" ;
    }

    /**
     * 对用户在注册表单上输入的数据进行校验(服务端校验)
     * @param holder 用来获取请求参数的对象
     * @param attrs 用来保存提示信息的对象
     * @return 当校验失败时返回false，仅当全部校验通过时返回true
     */
    private boolean validate( ParameterHolder holder , RedirectAttributes attrs ){

        String identifier = holder.getString( "loginName" );
        if( identifier == null || identifier.trim().isEmpty() ) {
            attrs.addFlashAttribute(MESSAGE_NAME, "登录名称不能为空" );
            return false ;
        }

        String passwd1 = holder.getString( "password" );
        if( passwd1 == null || passwd1.trim().isEmpty() ) {
            attrs.addFlashAttribute(MESSAGE_NAME, "密码不能为空" );
            return false ;
        }

        String passwd2 = holder.getString( "confirm" );
        if( passwd2 == null || passwd2.trim().isEmpty() ) {
            attrs.addFlashAttribute(MESSAGE_NAME, "你没有再次确认密码" );
            return false ;
        }

        String captchaInput = holder.getString( "captcha" );
        if( captchaInput == null || captchaInput.trim().isEmpty() ) {
            attrs.addFlashAttribute(MESSAGE_NAME, "验证码不能为空" );
            return false ;
        }

        // 注意这里使用了感叹号
        if( !passwd1.trim().equals( passwd2.trim() ) ) { // 注意这里使用了感叹号
            attrs.addFlashAttribute(MESSAGE_NAME, "两次输入的密码不一致" );
            return false ;
        }

        HttpServletRequest request = RequestHolder.getCurrentRequest(); // 获得当前的请求对象
        HttpSession session = request.getSession() ; // 通过当前请求对象获取当前会话对象
        String code = (String)session.getAttribute( CAPTCHA_NAME );

        // 注意这里使用了感叹号 、注意这里的比较是忽略大小写的
        if( !code.trim().equalsIgnoreCase( captchaInput.trim() ) ) { // 注意这里使用了感叹号
            attrs.addFlashAttribute(MESSAGE_NAME, "你的验证码输入错误" );
            return false ;
        }

        return true ;
    }

    @RequestMapping( path = "/action/sign/up" )
    public String signUpAction( ParameterHolder holder , RedirectAttributes attrs ){
        // 声明一个变量，该变量的值表示注册失败之后所去往的路径
        final String fail = "redirect:/student/page/sign/up" ;
        // 声明一个变量，该变量的值表示注册成功之后所去往的路径
        final String success = "redirect:/student/page/sign/in" ;

        // 注意这里使用了感叹号
        if( !this.validate( holder , attrs ) ) { // 注意这里使用了感叹号
            return fail ;
        }

        // 从请求中提取我们需要的请求参数
        String loginName = holder.getString( "loginName" );
        String password = holder.getString( "password" );

        // 创建Student对象
        Student s = new Student();
        s.setLoginName( loginName ); // 将 登录名称 保存到Student的实例变量中
        s.setPassword( password ); // 将 密码 保存到Student的实例变量中

        boolean x = studentDao.save( s ); // 保存学生对象到数据库
        if( x ) {
            attrs.addFlashAttribute(MESSAGE_NAME, "注册成功，可以登录了" );
            return success;
        } else {
            attrs.addFlashAttribute(MESSAGE_NAME, "注册失败" );
            return fail ;
        }
    }

    @RequestMapping( path = "/captcha" )
    public void captcha( HttpSession session ){
        System.out.println( "= = = = = captcha = = = = =" );

        // 获得当前的响应对象(HttpServletResponse)
        HttpServletResponse response = ResponseHolder.getCurrentResponse();

        try {
            // 获得可以输出验证码图片的字节流
            OutputStream output = response.getOutputStream();
            // 调用 GraphicHelper 类中的 create方法生成验证码图片并通过 output 输出该图片
            // 同时将 验证码图片上的内容 记录到一个 String 变量中
            String code = GraphicHelper.create( 6 , false , 180 , 40 , output , 50 );
            System.out.println( "生成的图片验证码内容是: " + code );

            // 将生成的验证码图片的内容保存到当前会话对象中
            session.setAttribute( CAPTCHA_NAME , code );// code 所对应的字符串就是需要保存的内容
        } catch ( IOException e ) {
            e.printStackTrace();
        }

    }

    @RequestMapping( path = "/action/sign/in" )
    public String signInAction( ParameterHolder holder , RedirectAttributes attrs , HttpSession session ){
        final String fail = "redirect:/student/page/sign/up" ;
        final String success = "redirect:/student/page/main" ;

        // 这里省略了数据校验过程( 可以参照 validate 方法来实现 )

        String loginName = holder.getString( "loginName" );
        // 获取到用户在页面上输入的明文密码
        String password = holder.getString( "password" );

        Student stu = studentDao.find( loginName );

        if( stu == null ) {
            attrs.addFlashAttribute( MESSAGE_NAME , "登录名称错误" );
            return fail ;
        } else {
            String passwd = stu.getPassword() ; // 注意，这个密码是来自数据库的，被加密过的密码
            // 为了能够比较，所以需要将 用户在表单中输入的数据先加密，然后再比较
            String encrypted = EncryptHelper.encrypt( password.trim() , EncryptType.SHA1 );
            // 比较 用户输入的密码在加密后 是否与数据库中存储的密码相同
            if( encrypted.equals( passwd ) ) {
                // 若相同，就登录
                session.setAttribute( SIGN_IN_NAME , stu ) ; // 所谓登录，就是将当前 学生对象 绑定到 会话对象中
                return success ; // 去往登录成功后的页面
            } else {
                // 若不同，就返回登录页面
                return fail ;
            }
        }
    }

    @RequestMapping( path = "/page/main" )
    public String mainPage(){
        return "/WEB-INF/assets/main.html" ;
    }

    @RequestMapping( path = "/action/sign/out" )
    public String signOutAction( HttpSession session ) {
        session.invalidate(); // 废弃当前会话对象(其中包含的数据将全部丢失)
        return "redirect:/student/page/main" ;
    }

}